YUV格式学习:YUV422P、YV16、NV16、NV61格式转换成RGB24 您所在的位置:网站首页 ffplay yuv格式 YUV格式学习:YUV422P、YV16、NV16、NV61格式转换成RGB24

YUV格式学习:YUV422P、YV16、NV16、NV61格式转换成RGB24

2023-10-09 10:41| 来源: 网络整理| 查看: 265

对于YUV422的格式,网上有一大堆资料,这里就不说了。直奔主题,给出如何转换的函数,一如既往,只用代码说事。

YUV422有打包格式(Packed),一如前文所述。同时还有平面格式(Planar),即Y、U、V是分开存储的,每个分量占一块地方,其中Y为width*height,而U、V合占width*height,该种格式每个像素占16比特。根据U、V的顺序,分出2种格式,U前V后即YUV422P,也叫I422,V前U后,叫YV16(YV表示Y后面跟着V,16表示16bit)。另外,还有一种变态的半平面格式(Semi-planar),即Y单独占一块地方,但其后U、V又紧挨着排在一起,根据U、V的顺序,又有2种,U前V后叫NV16,在国内好像很多人叫它为YUV422SP格式;V前U后叫NV61。不过这种格式似乎不太受VLC欢迎(具体可去看看VLC的wiki)。

先给出YUV422平面格式的转换函数,如下:

/** 内存分布 w +--------------------+ |Y0Y1Y2Y3... | |... | h |... | | | +--------------------+ |U0U1 | |... | h |... | | | +----------+ |V0V1 | |... | h |... | | | +----------+ w/2 */ void yuv422p_to_rgb24(YUV_TYPE type, unsigned char* yuv422p, unsigned char* rgb, int width, int height) { int y, cb, cr; int r, g, b; int i = 0; unsigned char* p_y; unsigned char* p_u; unsigned char* p_v; unsigned char* p_rgb; p_y = yuv422p; p_u = p_y + width * height; p_v = p_u + width * height / 2; if (type == FMT_YV16) { p_v = p_y + width * height; p_u = p_u + width * height / 2; } p_rgb = rgb; init_yuv422p_table(); for (i = 0; i < width * height / 2; i++) { y = p_y[0]; cb = p_u[0]; cr = p_v[0]; r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value // 此处可调整RGB排序,BMP图片排序为BGR // 默认排序为:RGB p_rgb[0] = r; p_rgb[1] = g; p_rgb[2] = b; y = p_y[1]; cb = p_u[0]; cr = p_v[0]; r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value p_rgb[3] = r; p_rgb[4] = g; p_rgb[5] = b; p_y += 2; p_u += 1; p_v += 1; p_rgb += 6; } }

接着给出NV16、NV61转换成RGB的函数,如下:

/** 内存分布 w +--------------------+ |Y0Y1Y2Y3... | |... | h |... | | | +--------------------+ |U0V0U1V1 | |... | h |... | | | +--------------------+ w/2 UV交织为NV16,VU交织为NV61 可以与上一函数合并,但方便查看,还是不合并 */ void yuv422sp_to_rgb24(YUV_TYPE type, unsigned char* yuv422sp, unsigned char* rgb, int width, int height) { int y, cb, cr; int r, g, b; int i = 0; unsigned char* p_y; unsigned char* p_uv; unsigned char* p_rgb; p_y = yuv422sp; p_uv = p_y + width * height; // uv分量在Y后面 p_rgb = rgb; init_yuv422p_table(); for (i = 0; i < width * height / 2; i++) { y = p_y[0]; if (type == FMT_NV16) { cb = p_uv[0]; cr = p_uv[1]; // v紧跟u,在u的下一个位置 } if (type == FMT_NV61) { cr = p_uv[0]; cb = p_uv[1]; // u紧跟v,在v的下一个位置 } r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value // 此处可调整RGB排序,BMP图片排序为BGR // 默认排序为:RGB p_rgb[0] = r; p_rgb[1] = g; p_rgb[2] = b; y = p_y[1]; if (type == FMT_NV16) { cb = p_uv[0]; cr = p_uv[1]; } if (type == FMT_NV61) { cr = p_uv[0]; cb = p_uv[1]; } r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000)); //R value b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000)); //B value g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value p_rgb[3] = r; p_rgb[4] = g; p_rgb[5] = b; p_y += 2; p_uv += 2; p_rgb += 6; } }

参考资料:

http://www.fourcc.org/yuv.php

https://wiki.videolan.org/YUV/

李迟 2015.8.5 晚上

 


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有